﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace SBBitmap
{
    public class WarpBitmap
    {
        #region Class-Member

        public byte[] m_imagevalues;
        public IntPtr m_firstline;
        private BitmapData m_bmpdata;
        int m_width;
        int m_height;
        private int m_stride;
        private Rectangle m_rec;
        private Bitmap m_bmp;
        private int m_bytes;
        private PixelFormat m_pixelformat;
        private ColorPalette m_colorPalette;
        //private Color color;
        private bool locked;

        #endregion

        #region Constructors

        public WarpBitmap(String ImageFileName)
        {
            //m_bmp = new Bitmap(ImageFileName);
            m_bmp = new Bitmap(ImageFileName);
            Init();
        }
        public WarpBitmap(Bitmap Bitmap)
        {
            m_bmp = Bitmap;
            Init();
        }
        public WarpBitmap(int width, int height, PixelFormat pixelformat)
        {
            m_bmp = new Bitmap(width, height, pixelformat);
            Init();
        }

        #endregion

        #region Class-Methods

        void Init()
        {
            m_width = m_bmp.Width;
            m_height = m_bmp.Height;
            m_pixelformat = m_bmp.PixelFormat;
            m_colorPalette = m_bmp.Palette;


            //Wenn Indexed-Pixelformat vorliegt, in 24bppRGB-Format umwandeln
            if ((m_pixelformat == PixelFormat.Format32bppRgb) || (m_pixelformat == PixelFormat.Format8bppIndexed) || (m_pixelformat == PixelFormat.Format4bppIndexed) || (m_pixelformat == PixelFormat.Format1bppIndexed))
            {
                Point ulCorner = new Point(0, 0);

                Bitmap m_bmptemp = new Bitmap(m_bmp.Width, m_bmp.Height, PixelFormat.Format24bppRgb);
                m_pixelformat = PixelFormat.Format24bppRgb;
                Graphics bmp2 = Graphics.FromImage(m_bmptemp);
                bmp2.DrawImage(m_bmp, ulCorner);
                m_bmp = m_bmptemp;
                bmp2.Dispose();
            }

            unsafe
            {
                // Lock the bitmap's bits.  
                m_rec = new Rectangle(0, 0, m_width, m_height);
                m_bmpdata = m_bmp.LockBits(m_rec, System.Drawing.Imaging.ImageLockMode.ReadWrite, m_pixelformat);
                locked = true;
                m_stride = m_bmpdata.Stride;
                // Get the address of the first line.
                m_firstline = m_bmpdata.Scan0;
                // Declare an array to hold the bytes of the bitmap.
                m_bytes = m_stride * m_height;
                m_imagevalues = new byte[m_bytes];
                // Copy the RGB values into the array.
                System.Runtime.InteropServices.Marshal.Copy(m_firstline, m_imagevalues, 0, m_bytes);
            }
        }
        //---------------------------------------------------------------------
        public void SetPixel(int x, int y, Color color)
        {
            m_imagevalues[y * m_stride + x * 3] = color.B;
            m_imagevalues[y * m_stride + x * 3 + 1] = color.G;
            m_imagevalues[y * m_stride + x * 3 + 2] = color.R;
        }
        //---------------------------------------------------------------------
        public void SetPixel(int x, int y, byte grayval)
        {
            switch (m_pixelformat)
            {
                case PixelFormat.Format8bppIndexed:
                    m_imagevalues[y * m_stride + x] = grayval;
                    //m_colorPalette.Entries[m_imagevalues[y * stride + x]];
                    break;
                case PixelFormat.Format24bppRgb:
                    m_imagevalues[y * m_stride + x * 3] = grayval;
                    m_imagevalues[y * m_stride + x * 3 + 1] = grayval;
                    m_imagevalues[y * m_stride + x * 3 + 2] = grayval;
                    break;
            }

        }
        //---------------------------------------------------------------------
        public void SetPixel(int x, int y, byte R, byte G, byte B)
        {
            switch (m_pixelformat)
            {
                case PixelFormat.Format24bppRgb:
                    m_imagevalues[y * m_stride + x * 3] = B;
                    m_imagevalues[y * m_stride + x * 3 + 1] = G;
                    m_imagevalues[y * m_stride + x * 3 + 2] = R;
                    break;
            }
        }
        //---------------------------------------------------------------------
        public Color GetPixel(int x, int y)
        {
            return Color.FromArgb(m_imagevalues[y * m_stride + x * 3 + 2], m_imagevalues[y * m_stride + x * 3 + 1], m_imagevalues[y * m_stride + x * 3]);
        }
        //---------------------------------------------------------------------
        public byte GetPixelB(int x, int y)
        {
            switch (m_pixelformat)
            {
                case PixelFormat.Format24bppRgb:
                    //Für 24bpp-Pixelformat mit nur Grauwerten...
                    return m_imagevalues[y * m_stride + x * 3];
                case PixelFormat.Format8bppIndexed:

                    return m_imagevalues[y * m_stride + x];
                default: return 0;
            }
        }
        //---------------------------------------------------------------------
        public byte[] GetPixelC(int x, int y)
        {
            byte[] ret = new byte[3];
            ret[0] = m_imagevalues[y * m_stride + x * 3 + 2];
            ret[1] = m_imagevalues[y * m_stride + x * 3 + 1];
            ret[2] = m_imagevalues[y * m_stride + x * 3];
            return ret;
        }
        //---------------------------------------------------------------------
        #endregion

        #region Properties
        public bool Locked
        {
            set
            {
                m_bmp.UnlockBits(m_bmpdata);
                locked = value;
            }
        }
        public Bitmap Image
        {
            set
            {
                m_bmp = value;
                Init();
            }
            get
            {
                switch (m_pixelformat)
                {
                    case PixelFormat.Format24bppRgb:
                        if (locked == true)
                        {
                            System.Runtime.InteropServices.Marshal.Copy(m_imagevalues, 0, m_firstline, m_bytes);
                            m_bmp.UnlockBits(m_bmpdata);
                            locked = false;
                        }
                        return m_bmp;
                    case PixelFormat.Format8bppIndexed:
                        if (locked == true)
                        {
                            System.Runtime.InteropServices.Marshal.Copy(m_imagevalues, 0, m_firstline, m_bytes);
                            m_bmp.UnlockBits(m_bmpdata);
                            locked = false;
                        }
                        m_bmp.UnlockBits(m_bmpdata);
                        return m_bmp;
                }
                return null;
            }
        }
        public int Width
        {
            get
            {
                return m_width;
            }
        }
        public int Height
        {
            get
            {
                return m_height;
            }
        }
        public PixelFormat Pixelformat
        {
            get
            {
                return m_pixelformat;
            }
        }
        #endregion
    }
}
